
#include "SideElement.h"
#include "RayLine.h"
#include "LineSegment.h"
#include "MooseRandom.h"
#include "libmesh/fe_interface.h"
#include "libmesh/fe_type.h"

//#include "RandomInterface.h"
using namespace std;

SideElement::SideElement(const Elem *elem, const Point normal, Real transmissivity, Real absorptivity, Real diffuse_reflectivity, Real mirrors_reflectivity) :
 _transmissivity(transmissivity),
 _absorptivity(absorptivity),
 _diffuse_reflectivity(diffuse_reflectivity),
 _mirrors_reflectivity(mirrors_reflectivity),
 _elem(elem),
 _normal(normal)
{
}

RayLine SideElement::sendRay()
{
	Real xi = 1.0;
	Real eta = 1.0;
	Real theita = 2.0 * pi * MooseRandom::rand();
	Real phi = acos(1.0 - 2.0 * MooseRandom::rand());

	unsigned int dim = _elem->dim();
	Point p = _elem->centroid();

	if (dim == 2)
	{
		if (_elem->type() == TRI3)
		{
			while(xi + eta > 1.0)
			{
				xi = MooseRandom::rand();
				eta = MooseRandom::rand();
			}
		p = FEInterface::map(dim, FEType(), _elem, Point( xi, eta));
		}

		else if (_elem->type() == QUAD4)
		{
			Real S1_percent = ((_elem->point(1)) - (_elem->point(0))) * ((_elem->point(2)) - (_elem->point(0))) / (2.0 * _elem->volume());
			Real Rs = MooseRandom::rand();

			while(xi+eta>1.0)
			{
				xi = MooseRandom::rand();
				eta = MooseRandom::rand();
			}

			if(Rs < S1_percent)
				p = (1-xi-eta) * (_elem->point(0)) + xi * (_elem->point(1)) + eta * (_elem->point(2));

			else
				p = (1 - xi - eta) * (_elem->point(0)) + xi * (_elem->point(2)) + eta * (_elem->point(3));
		}

		else
			mooseError("产生随机位置时不支持的网格形状："/* << _elem->type()*/);

		Point O1 = p + _normal;

		Point M(cos(theita) * sin(phi), sin(theita) * sin(phi), cos(phi));
		M += O1;

		if((M - p).norm() < RaylineZero)
		{
			return RayLine(p, _normal);
		}

		else
		{
			return RayLine(p, (M - p).unit());
		}
	}

	else if (dim == 1)
	{
		xi = MooseRandom::rand();
		p = FEInterface::map(dim, FEType(), _elem, Point( (2 * xi - 1.0), 0.0));
		Point O1 = p + _normal;

		Point M(sin(theita) * sin(phi), cos(phi));
//		Point M(cos(theita),sin(theita));
		M += O1;

		if((M - p).norm() < RaylineZero)
		{
			return RayLine(p, _normal);
		}

		else
		{
			return RayLine(p, (M - p).unit());
		}
	}

	else // 1D
	{
		return RayLine(p, p + RaylineMax * _normal);
	}
}

RayLine SideElement::diffuseReflectRay(Point point)
{
	Real theita = 2 * pi * MooseRandom::rand();
	Real phi = acos(1 - 2 * MooseRandom::rand());

	unsigned int dim = _elem->dim();

	if (dim == 2)
	{
		Point O1 = point + _normal;

		Point M(cos(theita) * sin(phi), sin(theita) * sin(phi), cos(phi));
		M += O1;

		if((M - point).norm() < RaylineZero)
		{
			return RayLine(point, _normal);
		}
		else
		{
			return RayLine(point, (M - point).unit());
		}
	}

	else if (dim == 1)
	{
		Point O1 = point + _normal;
		Point M(sin(theita) * sin(phi), cos(phi));
		M = O1 + M;

		if((M - point).norm() < RaylineZero)
		{
			return RayLine(point, _normal);
		}

		else
		{
			return RayLine(point, (M - point).unit());
		}
	}

	else // 1D
	{
		return RayLine(point, _normal);
	}

}

RayLine SideElement::mirrorsReflectRay(RayLine* rayline, Point point)
{
	Point normal_in = rayline->_normal;
	Point normal_out = normal_in - _normal * (2 * (_normal * normal_in) / (normal_in.norm() * _normal.norm()));

	return RayLine(point, normal_out);
}
